import { ProFieldFC, useStyle } from '@ant-design/pro-components';
import { useFieldFetchData } from '@ant-design/pro-field/es/components/Select';
import {
  ProSchemaValueEnumObj,
  compatibleBorder,
  objectToMap,
  proFieldParsingText,
} from '@ant-design/pro-utils';
import { ConfigProvider, Spin } from 'antd';
import React, { useContext } from 'react';
import SfwAutoComplete, {
  SfwAutoCompleteProps,
} from '../../../form/SfwAutoComplete';

const Highlight: React.FC<{
  label: string;
  words: string[];
}> = ({ label, words }) => {
  const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
  const lightCls = getPrefixCls('pro-select-item-option-content-light');
  const optionCls = getPrefixCls('pro-select-item-option-content');

  // css
  const { wrapSSR } = useStyle('Highlight', (token) => {
    return {
      [`.${lightCls}`]: {
        color: token.colorPrimary,
      },
      [`.${optionCls}`]: {
        flex: 'auto',
        overflow: 'hidden',
        whiteSpace: 'nowrap',
        textOverflow: 'ellipsis',
      },
    };
  });

  const matchKeywordsRE = new RegExp(
    words
      .map((word) => word.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'))
      .join('|'),
    'gi',
  );

  let matchText = label;

  const elements: React.ReactNode[] = [];

  while (matchText.length) {
    const match = matchKeywordsRE.exec(matchText);
    if (!match) {
      elements.push(matchText);
      break;
    }

    const start = match.index;
    const matchLength = match[0].length + start;

    elements.push(
      matchText.slice(0, start),
      React.createElement(
        'span',
        {
          className: lightCls,
        },
        matchText.slice(start, matchLength),
      ),
    );
    matchText = matchText.slice(matchLength);
  }

  return wrapSSR(
    React.createElement(
      'div',
      {
        title: label,
        className: optionCls,
      },
      ...elements,
    ),
  );
};

/**
 * 代码片段组件 这个组件为了显示简单的配置，复杂的请使用更加重型的组件
 */
const FieldSfwAutoComplete: ProFieldFC<SfwAutoCompleteProps> = (props, ref) => {
  const { mode, label, fieldProps, bordered, id, ...rest } = props;
  const inputRef = React.useRef();
  const keyWordsRef = React.useRef<string>('');
  const { fieldNames } = fieldProps;
  const [loading, options, fetchData, resetData] = useFieldFetchData(props);

  React.useImperativeHandle(
    ref,
    () => ({
      ...(inputRef.current || {}),
      fetchData: (keyWord: string) => fetchData(keyWord),
    }),
    [fetchData],
  );

  const optionsValueEnum = React.useMemo(() => {
    if (mode !== 'read') return;

    const {
      label: labelPropsName = 'label',
      value: valuePropsName = 'label',
      options: optionsPropsName = 'options',
    } = fieldNames || {};

    const valuesMap = new Map();

    const traverseOptions = (_options: typeof options) => {
      if (!_options?.length) {
        return valuesMap;
      }
      const length = _options.length;
      let i = 0;
      while (i < length) {
        const cur = _options[i++];
        valuesMap.set(cur[valuePropsName], cur[labelPropsName]);
        traverseOptions(cur[optionsPropsName]);
      }
      return valuesMap;
    };

    return traverseOptions(options);
  }, [fieldNames, mode, options]);

  if (mode === 'read') {
    return (
      <>
        {proFieldParsingText(
          rest.text,
          objectToMap(optionsValueEnum) as unknown as ProSchemaValueEnumObj,
        )}
      </>
    );
  }

  if (mode === 'edit' || mode === 'update') {
    return (
      <SfwAutoComplete
        key="SfwAutoComplete"
        className={rest.className}
        style={{
          minWidth: 100,
          ...rest.style,
        }}
        {...compatibleBorder(bordered)}
        id={id}
        loading={loading}
        ref={inputRef}
        notFoundContent={
          loading ? <Spin size="small" /> : fieldProps?.notFoundContent
        }
        fetchData={(keyWord: string) => {
          keyWordsRef.current = keyWord ?? '';
          fetchData(keyWord);
        }}
        resetData={resetData}
        optionItemRender={(item: any) => {
          if (typeof item.label === 'string' && keyWordsRef.current) {
            return (
              <Highlight label={item.label} words={[keyWordsRef.current]} />
            );
          }
          return item.label;
        }}
        placeholder={'请选择'}
        label={label}
        {...fieldProps}
        options={options}
      />
    );
  }
  return null;
};

export default React.forwardRef(FieldSfwAutoComplete);
